/*
 * Binance Spot WebSocket API
 *
 * OpenAPI Specifications for the Binance Spot WebSocket API
 *
 * API documents:
 * - [Github web-socket-api documentation file](https://github.com/binance/binance-spot-api-docs/blob/master/web-socket-api.md)
 * - [General API information for web-socket-api on website](https://developers.binance.com/docs/binance-spot-api-docs/web-socket-api/general-api-information)
 *
 *
 * The version of the OpenAPI document: 1.0.0
 *
 *
 * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
 * https://openapi-generator.tech
 * Do not edit the class manually.
 */

#![allow(unused_imports)]
use serde::de::DeserializeOwned;
use serde_json::Value;
use std::{collections::BTreeMap, sync::Arc};

use crate::common::config::ConfigurationWebsocketApi;
use crate::common::models::WebsocketApiResponse;
use crate::common::utils::random_string;
use crate::common::websocket::{
    Subscription, WebsocketApi as WebsocketApiBase, WebsocketBase, WebsocketMessageSendOptions,
    WebsocketStream, create_stream_handler,
};
use crate::errors::WebsocketError;
use crate::models::{WebsocketEvent, WebsocketMode};

mod apis;
mod handle;
mod models;

pub use apis::*;
pub use handle::*;
pub use models::*;

const HAS_TIME_UNIT: bool = true;

#[derive(Clone)]
pub struct WebsocketApi {
    websocket_api_base: Arc<WebsocketApiBase>,

    account_api_client: AccountApiClient,
    auth_api_client: AuthApiClient,
    general_api_client: GeneralApiClient,
    market_api_client: MarketApiClient,
    trade_api_client: TradeApiClient,
    user_data_stream_api_client: UserDataStreamApiClient,
}

impl WebsocketApi {
    pub(crate) async fn connect(
        config: ConfigurationWebsocketApi,
        mode: Option<WebsocketMode>,
    ) -> anyhow::Result<Self> {
        let mut cfg = config;
        if let Some(m) = mode {
            cfg.mode = m;
        }
        if !HAS_TIME_UNIT {
            cfg.time_unit = None;
        }

        let websocket_api_base = WebsocketApiBase::new(cfg, vec![]);
        websocket_api_base.clone().connect().await?;

        Ok(Self {
            websocket_api_base: websocket_api_base.clone(),
            account_api_client: AccountApiClient::new(websocket_api_base.clone()),
            auth_api_client: AuthApiClient::new(websocket_api_base.clone()),
            general_api_client: GeneralApiClient::new(websocket_api_base.clone()),
            market_api_client: MarketApiClient::new(websocket_api_base.clone()),
            trade_api_client: TradeApiClient::new(websocket_api_base.clone()),
            user_data_stream_api_client: UserDataStreamApiClient::new(websocket_api_base.clone()),
        })
    }

    /// Subscribes to WebSocket events with a provided callback function.
    ///
    /// # Arguments
    ///
    /// * `callback` - A mutable function that will be called when a WebSocket event is received.
    ///   The callback takes a `WebsocketEvent` as its parameter.
    ///
    /// # Returns
    ///
    /// A `Subscription` that can be used to manage the event subscription.
    ///
    /// # Examples
    ///
    ///
    /// let subscription = `websocket_api.subscribe_on_ws_events(|event`| {
    ///     // Handle WebSocket event
    /// });
    ///
    pub fn subscribe_on_ws_events<F>(&self, callback: F) -> Subscription
    where
        F: FnMut(WebsocketEvent) + Send + 'static,
    {
        let base = Arc::clone(&self.websocket_api_base);
        base.common.events.subscribe(callback)
    }

    /// Unsubscribes from WebSocket events using the provided `Subscription`.
    ///
    /// # Arguments
    ///
    /// * `subscription` - The `Subscription` to unsubscribe from WebSocket events.
    ///
    /// # Examples
    ///
    ///
    /// let subscription = `websocket_api.subscribe_on_ws_events(|event`| {
    ///     // Handle WebSocket event
    /// });
    /// `websocket_api.unsubscribe_from_ws_events(subscription)`;
    ///
    pub fn unsubscribe_from_ws_events(&self, subscription: Subscription) {
        subscription.unsubscribe();
    }

    /// Disconnects the WebSocket connection.
    ///
    /// # Returns
    ///
    /// A `Result` indicating whether the disconnection was successful.
    /// Returns an error if the disconnection fails.
    ///
    /// # Errors
    ///
    /// Returns an [`anyhow::Error`] if the connection fails.
    ///
    /// # Examples
    ///
    ///
    /// let result = `websocket_api.disconnect().await`;
    ///
    pub async fn disconnect(&self) -> anyhow::Result<()> {
        self.websocket_api_base
            .disconnect()
            .await
            .map_err(anyhow::Error::msg)
    }

    /// Sends a ping message to the WebSocket server to check the connection status.
    ///
    /// # Examples
    ///
    ///
    /// `websocket_api.ping_server().await`;
    ///
    ///
    /// This method sends a lightweight ping request to verify the WebSocket connection is still active.
    pub async fn ping_server(&self) {
        self.websocket_api_base.ping_server().await;
    }

    /// Checks if the WebSocket connection is currently active.
    ///
    /// # Returns
    ///
    /// A `bool` indicating whether the WebSocket connection is established and active.
    ///
    /// # Examples
    ///
    ///
    /// let `is_active` = `websocket_api.is_connected().await`;
    /// if `is_active` {
    ///     // WebSocket connection is active
    /// }
    ///
    ///
    /// This method provides a way to check the current status of the WebSocket connection.
    pub async fn is_connected(&self) -> bool {
        self.websocket_api_base.is_connected().await
    }

    /// Sends an unsigned WebSocket message with the specified method and payload.
    ///
    /// # Type Parameters
    ///
    /// * `R` - The response type to deserialize the message into.
    ///
    /// # Arguments
    ///
    /// * `method` - The WebSocket method to invoke.
    /// * `payload` - A map of key-value pairs representing the message payload.
    ///
    /// # Returns
    ///
    /// A `Result` containing the deserialized response or a `WebsocketError`.
    ///
    /// # Errors
    ///
    /// Returns a `WebsocketError` if the WebSocket connection fails or the response cannot be deserialized.
    ///
    /// # Examples
    ///
    ///
    /// let response = `websocket_api.send_message::`<ResponseType>("`method_name`", payload).await;
    ///
    pub async fn send_message<R: DeserializeOwned + Send + Sync + 'static>(
        &self,
        method: &str,
        payload: BTreeMap<String, Value>,
    ) -> Result<WebsocketApiResponse<R>, WebsocketError> {
        self.websocket_api_base
            .send_message::<R>(method, payload, WebsocketMessageSendOptions::new())
            .await?
            .into_iter()
            .next()
            .ok_or(WebsocketError::NoResponse)
    }

    /// Sends a signed WebSocket message with the specified method and payload.
    ///
    /// # Type Parameters
    ///
    /// * `R` - The response type to deserialize the message into.
    ///
    /// # Arguments
    ///
    /// * `method` - The WebSocket method to invoke.
    /// * `payload` - A map of key-value pairs representing the message payload.
    ///
    /// # Returns
    ///
    /// A `Result` containing the deserialized response or a `WebsocketError`.
    ///
    /// # Errors
    ///
    /// Returns a `WebsocketError` if the WebSocket connection fails or the response cannot be deserialized.
    ///
    /// # Examples
    ///
    ///
    /// let response = `websocket_api.send_signed_message::`<ResponseType>("`method_name`", payload).await;
    ///
    pub async fn send_signed_message<R: DeserializeOwned + Send + Sync + 'static>(
        &self,
        method: &str,
        payload: BTreeMap<String, Value>,
    ) -> Result<WebsocketApiResponse<R>, WebsocketError> {
        self.websocket_api_base
            .send_message::<R>(method, payload, WebsocketMessageSendOptions::new().signed())
            .await?
            .into_iter()
            .next()
            .ok_or(WebsocketError::NoResponse)
    }

    /// WebSocket Account Commission Rates
    ///
    /// Get current account commission rates.
    /// Weight: 20
    ///
    /// # Arguments
    ///
    /// - `params`: [`AccountCommissionParams`]
    ///   The parameters for this operation.
    ///
    /// # Returns
    ///
    /// [`WebsocketApiResponse<Box<models::AccountCommissionResponseResult>>`] on success.
    ///
    /// # Errors
    ///
    /// Returns an [`anyhow::Error`] if the WebSocket request fails, if parameters are invalid, or if parsing the response fails.
    ///
    ///
    /// For full API details, see the [Binance API Documentation](https://developers.binance.com/docs/binance-spot-api-docs/websocket-api/account-requests#account-commission-rates-user_data).
    ///
    pub async fn account_commission(
        &self,
        params: AccountCommissionParams,
    ) -> anyhow::Result<WebsocketApiResponse<Box<models::AccountCommissionResponseResult>>> {
        self.account_api_client.account_commission(params).await
    }

    /// WebSocket Unfilled Order Count
    ///
    /// Query your current unfilled order count for all intervals.
    /// Weight: 40
    ///
    /// # Arguments
    ///
    /// - `params`: [`AccountRateLimitsOrdersParams`]
    ///   The parameters for this operation.
    ///
    /// # Returns
    ///
    /// [`WebsocketApiResponse<Vec<models::AccountRateLimitsOrdersResponseResultInner>>`] on success.
    ///
    /// # Errors
    ///
    /// Returns an [`anyhow::Error`] if the WebSocket request fails, if parameters are invalid, or if parsing the response fails.
    ///
    ///
    /// For full API details, see the [Binance API Documentation](https://developers.binance.com/docs/binance-spot-api-docs/websocket-api/account-requests#unfilled-order-count-user_data).
    ///
    pub async fn account_rate_limits_orders(
        &self,
        params: AccountRateLimitsOrdersParams,
    ) -> anyhow::Result<WebsocketApiResponse<Vec<models::AccountRateLimitsOrdersResponseResultInner>>>
    {
        self.account_api_client
            .account_rate_limits_orders(params)
            .await
    }

    /// WebSocket Account information
    ///
    /// Query information about your account.
    /// Weight: 20
    ///
    /// # Arguments
    ///
    /// - `params`: [`AccountStatusParams`]
    ///   The parameters for this operation.
    ///
    /// # Returns
    ///
    /// [`WebsocketApiResponse<Box<models::AccountStatusResponseResult>>`] on success.
    ///
    /// # Errors
    ///
    /// Returns an [`anyhow::Error`] if the WebSocket request fails, if parameters are invalid, or if parsing the response fails.
    ///
    ///
    /// For full API details, see the [Binance API Documentation](https://developers.binance.com/docs/binance-spot-api-docs/websocket-api/account-requests#account-information-user_data).
    ///
    pub async fn account_status(
        &self,
        params: AccountStatusParams,
    ) -> anyhow::Result<WebsocketApiResponse<Box<models::AccountStatusResponseResult>>> {
        self.account_api_client.account_status(params).await
    }

    /// WebSocket Account order list history
    ///
    /// Query information about all your order lists, filtered by time range.
    /// Weight: 20
    ///
    /// # Arguments
    ///
    /// - `params`: [`AllOrderListsParams`]
    ///   The parameters for this operation.
    ///
    /// # Returns
    ///
    /// [`WebsocketApiResponse<Vec<models::AllOrderListsResponseResultInner>>`] on success.
    ///
    /// # Errors
    ///
    /// Returns an [`anyhow::Error`] if the WebSocket request fails, if parameters are invalid, or if parsing the response fails.
    ///
    ///
    /// For full API details, see the [Binance API Documentation](https://developers.binance.com/docs/binance-spot-api-docs/websocket-api/account-requests#account-order-list-history-user_data).
    ///
    pub async fn all_order_lists(
        &self,
        params: AllOrderListsParams,
    ) -> anyhow::Result<WebsocketApiResponse<Vec<models::AllOrderListsResponseResultInner>>> {
        self.account_api_client.all_order_lists(params).await
    }

    /// WebSocket Account order history
    ///
    /// Query information about all your orders – active, canceled, filled – filtered by time range.
    /// Weight: 20
    ///
    /// # Arguments
    ///
    /// - `params`: [`AllOrdersParams`]
    ///   The parameters for this operation.
    ///
    /// # Returns
    ///
    /// [`WebsocketApiResponse<Vec<models::AllOrdersResponseResultInner>>`] on success.
    ///
    /// # Errors
    ///
    /// Returns an [`anyhow::Error`] if the WebSocket request fails, if parameters are invalid, or if parsing the response fails.
    ///
    ///
    /// For full API details, see the [Binance API Documentation](https://developers.binance.com/docs/binance-spot-api-docs/websocket-api/account-requests#account-order-history-user_data).
    ///
    pub async fn all_orders(
        &self,
        params: AllOrdersParams,
    ) -> anyhow::Result<WebsocketApiResponse<Vec<models::AllOrdersResponseResultInner>>> {
        self.account_api_client.all_orders(params).await
    }

    /// WebSocket Account allocations
    ///
    /// Retrieves allocations resulting from SOR order placement.
    /// Weight: 20
    ///
    /// # Arguments
    ///
    /// - `params`: [`MyAllocationsParams`]
    ///   The parameters for this operation.
    ///
    /// # Returns
    ///
    /// [`WebsocketApiResponse<Vec<models::MyAllocationsResponseResultInner>>`] on success.
    ///
    /// # Errors
    ///
    /// Returns an [`anyhow::Error`] if the WebSocket request fails, if parameters are invalid, or if parsing the response fails.
    ///
    ///
    /// For full API details, see the [Binance API Documentation](https://developers.binance.com/docs/binance-spot-api-docs/websocket-api/account-requests#account-allocations-user_data).
    ///
    pub async fn my_allocations(
        &self,
        params: MyAllocationsParams,
    ) -> anyhow::Result<WebsocketApiResponse<Vec<models::MyAllocationsResponseResultInner>>> {
        self.account_api_client.my_allocations(params).await
    }

    /// WebSocket Account prevented matches
    ///
    /// Displays the list of orders that were expired due to STP.
    ///
    /// These are the combinations supported:
    ///
    /// * `symbol` + `preventedMatchId`
    /// * `symbol` + `orderId`
    /// * `symbol` + `orderId` + `fromPreventedMatchId` (`limit` will default to 500)
    /// * `symbol` + `orderId` + `fromPreventedMatchId` + `limit`
    /// Weight: Case                            | Weight
    /// ----                            | -----
    /// If `symbol` is invalid          | 2
    /// Querying by `preventedMatchId`  | 2
    /// Querying by `orderId`           | 20
    ///
    /// # Arguments
    ///
    /// - `params`: [`MyPreventedMatchesParams`]
    ///   The parameters for this operation.
    ///
    /// # Returns
    ///
    /// [`WebsocketApiResponse<Vec<models::MyPreventedMatchesResponseResultInner>>`] on success.
    ///
    /// # Errors
    ///
    /// Returns an [`anyhow::Error`] if the WebSocket request fails, if parameters are invalid, or if parsing the response fails.
    ///
    ///
    /// For full API details, see the [Binance API Documentation](https://developers.binance.com/docs/binance-spot-api-docs/websocket-api/account-requests#account-prevented-matches-user_data).
    ///
    pub async fn my_prevented_matches(
        &self,
        params: MyPreventedMatchesParams,
    ) -> anyhow::Result<WebsocketApiResponse<Vec<models::MyPreventedMatchesResponseResultInner>>>
    {
        self.account_api_client.my_prevented_matches(params).await
    }

    /// WebSocket Account trade history
    ///
    /// Query information about all your trades, filtered by time range.
    /// Weight: Condition| Weight|
    /// ---| ---
    /// |Without orderId|20|
    /// |With orderId|5|
    ///
    /// # Arguments
    ///
    /// - `params`: [`MyTradesParams`]
    ///   The parameters for this operation.
    ///
    /// # Returns
    ///
    /// [`WebsocketApiResponse<Vec<models::MyTradesResponseResultInner>>`] on success.
    ///
    /// # Errors
    ///
    /// Returns an [`anyhow::Error`] if the WebSocket request fails, if parameters are invalid, or if parsing the response fails.
    ///
    ///
    /// For full API details, see the [Binance API Documentation](https://developers.binance.com/docs/binance-spot-api-docs/websocket-api/account-requests#account-trade-history-user_data).
    ///
    pub async fn my_trades(
        &self,
        params: MyTradesParams,
    ) -> anyhow::Result<WebsocketApiResponse<Vec<models::MyTradesResponseResultInner>>> {
        self.account_api_client.my_trades(params).await
    }

    /// WebSocket Current open Order lists
    ///
    /// Query execution status of all open order lists.
    ///
    /// If you need to continuously monitor order status updates, please consider using WebSocket Streams:
    ///
    /// * `userDataStream.start` request
    /// * `executionReport` user data stream event
    /// Weight: 6
    ///
    /// # Arguments
    ///
    /// - `params`: [`OpenOrderListsStatusParams`]
    ///   The parameters for this operation.
    ///
    /// # Returns
    ///
    /// [`WebsocketApiResponse<Vec<models::OpenOrderListsStatusResponseResultInner>>`] on success.
    ///
    /// # Errors
    ///
    /// Returns an [`anyhow::Error`] if the WebSocket request fails, if parameters are invalid, or if parsing the response fails.
    ///
    ///
    /// For full API details, see the [Binance API Documentation](https://developers.binance.com/docs/binance-spot-api-docs/websocket-api/account-requests#current-open-order-lists-user_data).
    ///
    pub async fn open_order_lists_status(
        &self,
        params: OpenOrderListsStatusParams,
    ) -> anyhow::Result<WebsocketApiResponse<Vec<models::OpenOrderListsStatusResponseResultInner>>>
    {
        self.account_api_client
            .open_order_lists_status(params)
            .await
    }

    /// WebSocket Current open orders
    ///
    /// Query execution status of all open orders.
    ///
    /// If you need to continuously monitor order status updates, please consider using WebSocket Streams:
    ///
    /// * `userDataStream.start` request
    /// * `executionReport` user data stream event
    /// Weight: Adjusted based on the number of requested symbols:
    ///
    /// | Parameter | Weight |
    /// | --------- | ------ |
    /// | `symbol`  |      6 |
    /// | none      |     80 |
    ///
    /// # Arguments
    ///
    /// - `params`: [`OpenOrdersStatusParams`]
    ///   The parameters for this operation.
    ///
    /// # Returns
    ///
    /// [`WebsocketApiResponse<Vec<models::OpenOrdersStatusResponseResultInner>>`] on success.
    ///
    /// # Errors
    ///
    /// Returns an [`anyhow::Error`] if the WebSocket request fails, if parameters are invalid, or if parsing the response fails.
    ///
    ///
    /// For full API details, see the [Binance API Documentation](https://developers.binance.com/docs/binance-spot-api-docs/websocket-api/account-requests#current-open-orders-user_data).
    ///
    pub async fn open_orders_status(
        &self,
        params: OpenOrdersStatusParams,
    ) -> anyhow::Result<WebsocketApiResponse<Vec<models::OpenOrdersStatusResponseResultInner>>>
    {
        self.account_api_client.open_orders_status(params).await
    }

    /// WebSocket Query Order Amendments
    ///
    /// Queries all amendments of a single order.
    /// Weight: 4
    ///
    /// # Arguments
    ///
    /// - `params`: [`OrderAmendmentsParams`]
    ///   The parameters for this operation.
    ///
    /// # Returns
    ///
    /// [`WebsocketApiResponse<Vec<models::OrderAmendmentsResponseResultInner>>`] on success.
    ///
    /// # Errors
    ///
    /// Returns an [`anyhow::Error`] if the WebSocket request fails, if parameters are invalid, or if parsing the response fails.
    ///
    ///
    /// For full API details, see the [Binance API Documentation](https://developers.binance.com/docs/binance-spot-api-docs/websocket-api/account-requests#query-order-amendments-user_data).
    ///
    pub async fn order_amendments(
        &self,
        params: OrderAmendmentsParams,
    ) -> anyhow::Result<WebsocketApiResponse<Vec<models::OrderAmendmentsResponseResultInner>>> {
        self.account_api_client.order_amendments(params).await
    }

    /// WebSocket Query Order list
    ///
    /// Check execution status of an Order list.
    ///
    /// For execution status of individual orders, use `order.status`.
    /// Weight: 4
    ///
    /// # Arguments
    ///
    /// - `params`: [`OrderListStatusParams`]
    ///   The parameters for this operation.
    ///
    /// # Returns
    ///
    /// [`WebsocketApiResponse<Box<models::AllOrderListsResponseResultInner>>`] on success.
    ///
    /// # Errors
    ///
    /// Returns an [`anyhow::Error`] if the WebSocket request fails, if parameters are invalid, or if parsing the response fails.
    ///
    ///
    /// For full API details, see the [Binance API Documentation](https://developers.binance.com/docs/binance-spot-api-docs/websocket-api/account-requests#query-order-list-user_data).
    ///
    pub async fn order_list_status(
        &self,
        params: OrderListStatusParams,
    ) -> anyhow::Result<WebsocketApiResponse<Box<models::AllOrderListsResponseResultInner>>> {
        self.account_api_client.order_list_status(params).await
    }

    /// WebSocket Query order
    ///
    /// Check execution status of an order.
    /// Weight: 4
    ///
    /// # Arguments
    ///
    /// - `params`: [`OrderStatusParams`]
    ///   The parameters for this operation.
    ///
    /// # Returns
    ///
    /// [`WebsocketApiResponse<Box<models::OrderStatusResponseResult>>`] on success.
    ///
    /// # Errors
    ///
    /// Returns an [`anyhow::Error`] if the WebSocket request fails, if parameters are invalid, or if parsing the response fails.
    ///
    ///
    /// For full API details, see the [Binance API Documentation](https://developers.binance.com/docs/binance-spot-api-docs/websocket-api/account-requests#query-order-user_data).
    ///
    pub async fn order_status(
        &self,
        params: OrderStatusParams,
    ) -> anyhow::Result<WebsocketApiResponse<Box<models::OrderStatusResponseResult>>> {
        self.account_api_client.order_status(params).await
    }

    /// WebSocket Log in with API key
    ///
    /// Authenticate WebSocket connection using the provided API key.
    ///
    /// After calling `session.logon`, you can omit `apiKey` and `signature` parameters for future requests that require them.
    ///
    /// Note that only one API key can be authenticated.
    /// Calling `session.logon` multiple times changes the current authenticated API key.
    /// Weight: 2
    ///
    /// # Arguments
    ///
    /// - `params`: [`SessionLogonParams`]
    ///   The parameters for this operation.
    ///
    /// # Returns
    ///
    /// [`WebsocketApiResponse<Box<models::SessionLogonResponseResult>>`] on success.
    ///
    /// # Errors
    ///
    /// Returns an [`anyhow::Error`] if the WebSocket request fails, if parameters are invalid, or if parsing the response fails.
    ///
    ///
    /// For full API details, see the [Binance API Documentation](https://developers.binance.com/docs/binance-spot-api-docs/websocket-api/authentication-requests#log-in-with-api-key-signed).
    ///
    pub async fn session_logon(
        &self,
        params: SessionLogonParams,
    ) -> anyhow::Result<Vec<WebsocketApiResponse<Box<models::SessionLogonResponseResult>>>> {
        self.auth_api_client.session_logon(params).await
    }

    /// WebSocket Log out of the session
    ///
    /// Forget the API key previously authenticated.
    /// If the connection is not authenticated, this request does nothing.
    ///
    /// Note that the WebSocket connection stays open after `session.logout` request.
    /// You can continue using the connection,
    /// but now you will have to explicitly provide the `apiKey` and `signature` parameters where needed.
    /// Weight: 2
    ///
    /// # Arguments
    ///
    /// - `params`: [`SessionLogoutParams`]
    ///   The parameters for this operation.
    ///
    /// # Returns
    ///
    /// [`WebsocketApiResponse<Box<models::SessionLogoutResponseResult>>`] on success.
    ///
    /// # Errors
    ///
    /// Returns an [`anyhow::Error`] if the WebSocket request fails, if parameters are invalid, or if parsing the response fails.
    ///
    ///
    /// For full API details, see the [Binance API Documentation](https://developers.binance.com/docs/binance-spot-api-docs/websocket-api/authentication-requests#log-out-of-the-session).
    ///
    pub async fn session_logout(
        &self,
        params: SessionLogoutParams,
    ) -> anyhow::Result<Vec<WebsocketApiResponse<Box<models::SessionLogoutResponseResult>>>> {
        self.auth_api_client.session_logout(params).await
    }

    /// WebSocket Query session status
    ///
    /// Query the status of the WebSocket connection,
    /// inspecting which API key (if any) is used to authorize requests.
    /// Weight: 2
    ///
    /// # Arguments
    ///
    /// - `params`: [`SessionStatusParams`]
    ///   The parameters for this operation.
    ///
    /// # Returns
    ///
    /// [`WebsocketApiResponse<Box<models::SessionStatusResponseResult>>`] on success.
    ///
    /// # Errors
    ///
    /// Returns an [`anyhow::Error`] if the WebSocket request fails, if parameters are invalid, or if parsing the response fails.
    ///
    ///
    /// For full API details, see the [Binance API Documentation](https://developers.binance.com/docs/binance-spot-api-docs/websocket-api/authentication-requests#query-session-status).
    ///
    pub async fn session_status(
        &self,
        params: SessionStatusParams,
    ) -> anyhow::Result<WebsocketApiResponse<Box<models::SessionStatusResponseResult>>> {
        self.auth_api_client.session_status(params).await
    }

    /// WebSocket Exchange information
    ///
    /// Query current exchange trading rules, rate limits, and symbol information.
    /// Weight: 20
    ///
    /// # Arguments
    ///
    /// - `params`: [`ExchangeInfoParams`]
    ///   The parameters for this operation.
    ///
    /// # Returns
    ///
    /// [`WebsocketApiResponse<Box<models::ExchangeInfoResponseResult>>`] on success.
    ///
    /// # Errors
    ///
    /// Returns an [`anyhow::Error`] if the WebSocket request fails, if parameters are invalid, or if parsing the response fails.
    ///
    ///
    /// For full API details, see the [Binance API Documentation](https://developers.binance.com/docs/binance-spot-api-docs/websocket-api/general-requests#exchange-information).
    ///
    pub async fn exchange_info(
        &self,
        params: ExchangeInfoParams,
    ) -> anyhow::Result<WebsocketApiResponse<Box<models::ExchangeInfoResponseResult>>> {
        self.general_api_client.exchange_info(params).await
    }

    /// WebSocket Test connectivity
    ///
    /// Test connectivity to the WebSocket API.
    /// Weight: 1
    ///
    /// # Arguments
    ///
    /// - `params`: [`PingParams`]
    ///   The parameters for this operation.
    ///
    /// # Returns
    ///
    /// [`WebsocketApiResponse<serde_json::Value>`] on success.
    ///
    /// # Errors
    ///
    /// Returns an [`anyhow::Error`] if the WebSocket request fails, if parameters are invalid, or if parsing the response fails.
    ///
    ///
    /// For full API details, see the [Binance API Documentation](https://developers.binance.com/docs/binance-spot-api-docs/websocket-api/general-requests#test-connectivity).
    ///
    pub async fn ping(
        &self,
        params: PingParams,
    ) -> anyhow::Result<WebsocketApiResponse<serde_json::Value>> {
        self.general_api_client.ping(params).await
    }

    /// WebSocket Check server time
    ///
    /// Test connectivity to the WebSocket API and get the current server time.
    /// Weight: 1
    ///
    /// # Arguments
    ///
    /// - `params`: [`TimeParams`]
    ///   The parameters for this operation.
    ///
    /// # Returns
    ///
    /// [`WebsocketApiResponse<Box<models::TimeResponseResult>>`] on success.
    ///
    /// # Errors
    ///
    /// Returns an [`anyhow::Error`] if the WebSocket request fails, if parameters are invalid, or if parsing the response fails.
    ///
    ///
    /// For full API details, see the [Binance API Documentation](https://developers.binance.com/docs/binance-spot-api-docs/websocket-api/general-requests#check-server-time).
    ///
    pub async fn time(
        &self,
        params: TimeParams,
    ) -> anyhow::Result<WebsocketApiResponse<Box<models::TimeResponseResult>>> {
        self.general_api_client.time(params).await
    }

    /// WebSocket Current average price
    ///
    /// Get current average price for a symbol.
    /// Weight: 2
    ///
    /// # Arguments
    ///
    /// - `params`: [`AvgPriceParams`]
    ///   The parameters for this operation.
    ///
    /// # Returns
    ///
    /// [`WebsocketApiResponse<Box<models::AvgPriceResponseResult>>`] on success.
    ///
    /// # Errors
    ///
    /// Returns an [`anyhow::Error`] if the WebSocket request fails, if parameters are invalid, or if parsing the response fails.
    ///
    ///
    /// For full API details, see the [Binance API Documentation](https://developers.binance.com/docs/binance-spot-api-docs/websocket-api/market-data-requests#current-average-price).
    ///
    pub async fn avg_price(
        &self,
        params: AvgPriceParams,
    ) -> anyhow::Result<WebsocketApiResponse<Box<models::AvgPriceResponseResult>>> {
        self.market_api_client.avg_price(params).await
    }

    /// WebSocket Order book
    ///
    /// Get current order book.
    ///
    /// Note that this request returns limited market depth.
    ///
    /// If you need to continuously monitor order book updates, please consider using WebSocket Streams:
    ///
    /// * `<symbol>@depth<levels>`
    /// * `<symbol>@depth`
    ///
    /// You can use `depth` request together with `<symbol>@depth` streams to [maintain a local order book](web-socket-streams.md#how-to-manage-a-local-order-book-correctly).
    /// Weight: Adjusted based on the limit:
    ///
    /// |  Limit    | Weight |
    /// |:---------:|:------:|
    /// |     1–100 |      5 |
    /// |   101–500 |      25|
    /// |  501–1000 |     50 |
    /// | 1001–5000 |     250 |
    ///
    /// # Arguments
    ///
    /// - `params`: [`DepthParams`]
    ///   The parameters for this operation.
    ///
    /// # Returns
    ///
    /// [`WebsocketApiResponse<Box<models::DepthResponseResult>>`] on success.
    ///
    /// # Errors
    ///
    /// Returns an [`anyhow::Error`] if the WebSocket request fails, if parameters are invalid, or if parsing the response fails.
    ///
    ///
    /// For full API details, see the [Binance API Documentation](https://developers.binance.com/docs/binance-spot-api-docs/websocket-api/market-data-requests#order-book).
    ///
    pub async fn depth(
        &self,
        params: DepthParams,
    ) -> anyhow::Result<WebsocketApiResponse<Box<models::DepthResponseResult>>> {
        self.market_api_client.depth(params).await
    }

    /// WebSocket Klines
    ///
    /// Get klines (candlestick bars).
    ///
    /// Klines are uniquely identified by their open & close time.
    ///
    /// If you need access to real-time kline updates, please consider using WebSocket Streams:
    ///
    /// * `<symbol>@kline_<interval>`
    ///
    /// If you need historical kline data,
    /// please consider using [data.binance.vision](https://github.com/binance/binance-public-data/#klines).
    /// Weight: 2
    ///
    /// # Arguments
    ///
    /// - `params`: [`KlinesParams`]
    ///   The parameters for this operation.
    ///
    /// # Returns
    ///
    /// [`WebsocketApiResponse<Vec<Vec<models::KlinesItemInner>>>`] on success.
    ///
    /// # Errors
    ///
    /// Returns an [`anyhow::Error`] if the WebSocket request fails, if parameters are invalid, or if parsing the response fails.
    ///
    ///
    /// For full API details, see the [Binance API Documentation](https://developers.binance.com/docs/binance-spot-api-docs/websocket-api/market-data-requests#klines).
    ///
    pub async fn klines(
        &self,
        params: KlinesParams,
    ) -> anyhow::Result<WebsocketApiResponse<Vec<Vec<models::KlinesItemInner>>>> {
        self.market_api_client.klines(params).await
    }

    /// WebSocket Rolling window price change statistics
    ///
    /// Get rolling window price change statistics with a custom window.
    ///
    /// This request is similar to `ticker.24hr`,
    /// but statistics are computed on demand using the arbitrary window you specify.
    /// Weight: Adjusted based on the number of requested symbols:
    ///
    /// | Symbols | Weight |
    /// |:-------:|:------:|
    /// |    1–50 | 4 per symbol |
    /// |  51–100 |    200 |
    ///
    /// # Arguments
    ///
    /// - `params`: [`TickerParams`]
    ///   The parameters for this operation.
    ///
    /// # Returns
    ///
    /// [`WebsocketApiResponse<models::TickerResponse>`] on success.
    ///
    /// # Errors
    ///
    /// Returns an [`anyhow::Error`] if the WebSocket request fails, if parameters are invalid, or if parsing the response fails.
    ///
    ///
    /// For full API details, see the [Binance API Documentation](https://developers.binance.com/docs/binance-spot-api-docs/websocket-api/market-data-requests#rolling-window-price-change-statistics).
    ///
    pub async fn ticker(
        &self,
        params: TickerParams,
    ) -> anyhow::Result<WebsocketApiResponse<models::TickerResponse>> {
        self.market_api_client.ticker(params).await
    }

    /// WebSocket 24hr ticker price change statistics
    ///
    /// Get 24-hour rolling window price change statistics.
    ///
    /// If you need to continuously monitor trading statistics, please consider using WebSocket Streams:
    ///
    /// * `<symbol>@ticker` or `!ticker@arr`
    /// * `<symbol>@miniTicker` or `!miniTicker@arr`
    ///
    /// If you need different window sizes,
    /// use the `ticker` request.
    /// Weight: Adjusted based on the number of requested symbols:
    ///
    /// | Symbols     | Weight |
    /// |:-----------:|:------:|
    /// |        1–20 |      2 |
    /// |      21–100 |     40 |
    /// | 101 or more |     80 |
    /// | all symbols |     80 |
    ///
    /// # Arguments
    ///
    /// - `params`: [`Ticker24hrParams`]
    ///   The parameters for this operation.
    ///
    /// # Returns
    ///
    /// [`WebsocketApiResponse<models::Ticker24hrResponse>`] on success.
    ///
    /// # Errors
    ///
    /// Returns an [`anyhow::Error`] if the WebSocket request fails, if parameters are invalid, or if parsing the response fails.
    ///
    ///
    /// For full API details, see the [Binance API Documentation](https://developers.binance.com/docs/binance-spot-api-docs/websocket-api/market-data-requests#24hr-ticker-price-change-statistics).
    ///
    pub async fn ticker24hr(
        &self,
        params: Ticker24hrParams,
    ) -> anyhow::Result<WebsocketApiResponse<models::Ticker24hrResponse>> {
        self.market_api_client.ticker24hr(params).await
    }

    /// WebSocket Symbol order book ticker
    ///
    /// Get the current best price and quantity on the order book.
    ///
    /// If you need access to real-time order book ticker updates, please consider using WebSocket Streams:
    ///
    /// * `<symbol>@bookTicker`
    /// Weight: Adjusted based on the number of requested symbols:
    ///
    /// | Parameter | Weight |
    /// | --------- |:------:|
    /// | `symbol`  |      2 |
    /// | `symbols` |      4 |
    /// | none      |      4 |
    ///
    /// # Arguments
    ///
    /// - `params`: [`TickerBookParams`]
    ///   The parameters for this operation.
    ///
    /// # Returns
    ///
    /// [`WebsocketApiResponse<models::TickerBookResponse>`] on success.
    ///
    /// # Errors
    ///
    /// Returns an [`anyhow::Error`] if the WebSocket request fails, if parameters are invalid, or if parsing the response fails.
    ///
    ///
    /// For full API details, see the [Binance API Documentation](https://developers.binance.com/docs/binance-spot-api-docs/websocket-api/market-data-requests#symbol-order-book-ticker).
    ///
    pub async fn ticker_book(
        &self,
        params: TickerBookParams,
    ) -> anyhow::Result<WebsocketApiResponse<models::TickerBookResponse>> {
        self.market_api_client.ticker_book(params).await
    }

    /// WebSocket Symbol price ticker
    ///
    /// Get the latest market price for a symbol.
    ///
    /// If you need access to real-time price updates, please consider using WebSocket Streams:
    ///
    /// * `<symbol>@aggTrade`
    /// * `<symbol>@trade`
    /// Weight: Adjusted based on the number of requested symbols:
    ///
    /// | Parameter | Weight |
    /// | --------- |:------:|
    /// | `symbol`  |      2 |
    /// | `symbols` |      4 |
    /// | none      |      4 |
    ///
    /// # Arguments
    ///
    /// - `params`: [`TickerPriceParams`]
    ///   The parameters for this operation.
    ///
    /// # Returns
    ///
    /// [`WebsocketApiResponse<models::TickerPriceResponse>`] on success.
    ///
    /// # Errors
    ///
    /// Returns an [`anyhow::Error`] if the WebSocket request fails, if parameters are invalid, or if parsing the response fails.
    ///
    ///
    /// For full API details, see the [Binance API Documentation](https://developers.binance.com/docs/binance-spot-api-docs/websocket-api/market-data-requests#symbol-price-ticker).
    ///
    pub async fn ticker_price(
        &self,
        params: TickerPriceParams,
    ) -> anyhow::Result<WebsocketApiResponse<models::TickerPriceResponse>> {
        self.market_api_client.ticker_price(params).await
    }

    /// WebSocket Trading Day Ticker
    ///
    /// Price change statistics for a trading day.
    /// Weight: 4 for each requested <tt>symbol</tt>. <br/><br/> The weight for this request will cap at 200 once the number of `symbols` in the request is more than 50.
    ///
    /// # Arguments
    ///
    /// - `params`: [`TickerTradingDayParams`]
    ///   The parameters for this operation.
    ///
    /// # Returns
    ///
    /// [`WebsocketApiResponse<Vec<models::TickerTradingDayResponseResultInner>>`] on success.
    ///
    /// # Errors
    ///
    /// Returns an [`anyhow::Error`] if the WebSocket request fails, if parameters are invalid, or if parsing the response fails.
    ///
    ///
    /// For full API details, see the [Binance API Documentation](https://developers.binance.com/docs/binance-spot-api-docs/websocket-api/market-data-requests#trading-day-ticker).
    ///
    pub async fn ticker_trading_day(
        &self,
        params: TickerTradingDayParams,
    ) -> anyhow::Result<WebsocketApiResponse<Vec<models::TickerTradingDayResponseResultInner>>>
    {
        self.market_api_client.ticker_trading_day(params).await
    }

    /// WebSocket Aggregate trades
    ///
    /// Get aggregate trades.
    ///
    /// An *aggregate trade* (aggtrade) represents one or more individual trades.
    /// Trades that fill at the same time, from the same taker order, with the same price –
    /// those trades are collected into an aggregate trade with total quantity of the individual trades.
    ///
    /// If you need access to real-time trading activity, please consider using WebSocket Streams:
    ///
    /// * `<symbol>@aggTrade`
    ///
    /// If you need historical aggregate trade data,
    /// please consider using [data.binance.vision](https://github.com/binance/binance-public-data/#aggtrades).
    /// Weight: 4
    ///
    /// # Arguments
    ///
    /// - `params`: [`TradesAggregateParams`]
    ///   The parameters for this operation.
    ///
    /// # Returns
    ///
    /// [`WebsocketApiResponse<Vec<models::TradesAggregateResponseResultInner>>`] on success.
    ///
    /// # Errors
    ///
    /// Returns an [`anyhow::Error`] if the WebSocket request fails, if parameters are invalid, or if parsing the response fails.
    ///
    ///
    /// For full API details, see the [Binance API Documentation](https://developers.binance.com/docs/binance-spot-api-docs/websocket-api/market-data-requests#aggregate-trades).
    ///
    pub async fn trades_aggregate(
        &self,
        params: TradesAggregateParams,
    ) -> anyhow::Result<WebsocketApiResponse<Vec<models::TradesAggregateResponseResultInner>>> {
        self.market_api_client.trades_aggregate(params).await
    }

    /// WebSocket Historical trades
    ///
    /// Get historical trades.
    /// Weight: 25
    ///
    /// # Arguments
    ///
    /// - `params`: [`TradesHistoricalParams`]
    ///   The parameters for this operation.
    ///
    /// # Returns
    ///
    /// [`WebsocketApiResponse<Vec<models::TradesHistoricalResponseResultInner>>`] on success.
    ///
    /// # Errors
    ///
    /// Returns an [`anyhow::Error`] if the WebSocket request fails, if parameters are invalid, or if parsing the response fails.
    ///
    ///
    /// For full API details, see the [Binance API Documentation](https://developers.binance.com/docs/binance-spot-api-docs/websocket-api/market-data-requests#historical-trades).
    ///
    pub async fn trades_historical(
        &self,
        params: TradesHistoricalParams,
    ) -> anyhow::Result<WebsocketApiResponse<Vec<models::TradesHistoricalResponseResultInner>>>
    {
        self.market_api_client.trades_historical(params).await
    }

    /// WebSocket Recent trades
    ///
    /// Get recent trades.
    ///
    /// If you need access to real-time trading activity, please consider using WebSocket Streams:
    ///
    /// * `<symbol>@trade`
    /// Weight: 25
    ///
    /// # Arguments
    ///
    /// - `params`: [`TradesRecentParams`]
    ///   The parameters for this operation.
    ///
    /// # Returns
    ///
    /// [`WebsocketApiResponse<Vec<models::TradesRecentResponseResultInner>>`] on success.
    ///
    /// # Errors
    ///
    /// Returns an [`anyhow::Error`] if the WebSocket request fails, if parameters are invalid, or if parsing the response fails.
    ///
    ///
    /// For full API details, see the [Binance API Documentation](https://developers.binance.com/docs/binance-spot-api-docs/websocket-api/market-data-requests#recent-trades).
    ///
    pub async fn trades_recent(
        &self,
        params: TradesRecentParams,
    ) -> anyhow::Result<WebsocketApiResponse<Vec<models::TradesRecentResponseResultInner>>> {
        self.market_api_client.trades_recent(params).await
    }

    /// WebSocket UI Klines
    ///
    /// Get klines (candlestick bars) optimized for presentation.
    ///
    /// This request is similar to `klines`, having the same parameters and response.
    /// `uiKlines` return modified kline data, optimized for presentation of candlestick charts.
    /// Weight: 2
    ///
    /// # Arguments
    ///
    /// - `params`: [`UiKlinesParams`]
    ///   The parameters for this operation.
    ///
    /// # Returns
    ///
    /// [`WebsocketApiResponse<Vec<Vec<models::KlinesItemInner>>>`] on success.
    ///
    /// # Errors
    ///
    /// Returns an [`anyhow::Error`] if the WebSocket request fails, if parameters are invalid, or if parsing the response fails.
    ///
    ///
    /// For full API details, see the [Binance API Documentation](https://developers.binance.com/docs/binance-spot-api-docs/websocket-api/market-data-requests#ui-klines).
    ///
    pub async fn ui_klines(
        &self,
        params: UiKlinesParams,
    ) -> anyhow::Result<WebsocketApiResponse<Vec<Vec<models::KlinesItemInner>>>> {
        self.market_api_client.ui_klines(params).await
    }

    /// WebSocket Cancel open orders
    ///
    /// Cancel all open orders on a symbol.
    /// This includes orders that are part of an order list.
    /// Weight: 1
    ///
    /// # Arguments
    ///
    /// - `params`: [`OpenOrdersCancelAllParams`]
    ///   The parameters for this operation.
    ///
    /// # Returns
    ///
    /// [`WebsocketApiResponse<Vec<models::OpenOrdersCancelAllResponseResultInner>>`] on success.
    ///
    /// # Errors
    ///
    /// Returns an [`anyhow::Error`] if the WebSocket request fails, if parameters are invalid, or if parsing the response fails.
    ///
    ///
    /// For full API details, see the [Binance API Documentation](https://developers.binance.com/docs/binance-spot-api-docs/websocket-api/trading-requests#cancel-open-orders-trade).
    ///
    pub async fn open_orders_cancel_all(
        &self,
        params: OpenOrdersCancelAllParams,
    ) -> anyhow::Result<WebsocketApiResponse<Vec<models::OpenOrdersCancelAllResponseResultInner>>>
    {
        self.trade_api_client.open_orders_cancel_all(params).await
    }

    /// WebSocket Order Amend Keep Priority
    ///
    /// Reduce the quantity of an existing open order.
    ///
    /// This adds 0 orders to the `EXCHANGE_MAX_ORDERS` filter and the `MAX_NUM_ORDERS` filter.
    ///
    /// Read [Order Amend Keep Priority FAQ](faqs/order_amend_keep_priority.md) to learn more.
    /// Weight: 4
    ///
    /// # Arguments
    ///
    /// - `params`: [`OrderAmendKeepPriorityParams`]
    ///   The parameters for this operation.
    ///
    /// # Returns
    ///
    /// [`WebsocketApiResponse<Box<models::OrderAmendKeepPriorityResponseResult>>`] on success.
    ///
    /// # Errors
    ///
    /// Returns an [`anyhow::Error`] if the WebSocket request fails, if parameters are invalid, or if parsing the response fails.
    ///
    ///
    /// For full API details, see the [Binance API Documentation](https://developers.binance.com/docs/binance-spot-api-docs/websocket-api/trading-requests#order-amend-keep-priority-trade).
    ///
    pub async fn order_amend_keep_priority(
        &self,
        params: OrderAmendKeepPriorityParams,
    ) -> anyhow::Result<WebsocketApiResponse<Box<models::OrderAmendKeepPriorityResponseResult>>>
    {
        self.trade_api_client
            .order_amend_keep_priority(params)
            .await
    }

    /// WebSocket Cancel order
    ///
    /// Cancel an active order.
    /// Weight: 1
    ///
    /// # Arguments
    ///
    /// - `params`: [`OrderCancelParams`]
    ///   The parameters for this operation.
    ///
    /// # Returns
    ///
    /// [`WebsocketApiResponse<Box<models::OrderCancelResponseResult>>`] on success.
    ///
    /// # Errors
    ///
    /// Returns an [`anyhow::Error`] if the WebSocket request fails, if parameters are invalid, or if parsing the response fails.
    ///
    ///
    /// For full API details, see the [Binance API Documentation](https://developers.binance.com/docs/binance-spot-api-docs/websocket-api/trading-requests#cancel-order-trade).
    ///
    pub async fn order_cancel(
        &self,
        params: OrderCancelParams,
    ) -> anyhow::Result<WebsocketApiResponse<Box<models::OrderCancelResponseResult>>> {
        self.trade_api_client.order_cancel(params).await
    }

    /// WebSocket Cancel and replace order
    ///
    /// Cancel an existing order and immediately place a new order instead of the canceled one.
    ///
    /// A new order that was not attempted (i.e. when `newOrderResult: NOT_ATTEMPTED`), will still increase the unfilled order count by 1.
    /// Weight: 1
    ///
    /// # Arguments
    ///
    /// - `params`: [`OrderCancelReplaceParams`]
    ///   The parameters for this operation.
    ///
    /// # Returns
    ///
    /// [`WebsocketApiResponse<Box<models::OrderCancelReplaceResponseResult>>`] on success.
    ///
    /// # Errors
    ///
    /// Returns an [`anyhow::Error`] if the WebSocket request fails, if parameters are invalid, or if parsing the response fails.
    ///
    ///
    /// For full API details, see the [Binance API Documentation](https://developers.binance.com/docs/binance-spot-api-docs/websocket-api/trading-requests#cancel-and-replace-order-trade).
    ///
    pub async fn order_cancel_replace(
        &self,
        params: OrderCancelReplaceParams,
    ) -> anyhow::Result<WebsocketApiResponse<Box<models::OrderCancelReplaceResponseResult>>> {
        self.trade_api_client.order_cancel_replace(params).await
    }

    /// WebSocket Cancel Order list
    ///
    /// Cancel an active order list.
    /// Weight: 1
    ///
    /// # Arguments
    ///
    /// - `params`: [`OrderListCancelParams`]
    ///   The parameters for this operation.
    ///
    /// # Returns
    ///
    /// [`WebsocketApiResponse<Box<models::OrderListCancelResponseResult>>`] on success.
    ///
    /// # Errors
    ///
    /// Returns an [`anyhow::Error`] if the WebSocket request fails, if parameters are invalid, or if parsing the response fails.
    ///
    ///
    /// For full API details, see the [Binance API Documentation](https://developers.binance.com/docs/binance-spot-api-docs/websocket-api/trading-requests#cancel-order-list-trade).
    ///
    pub async fn order_list_cancel(
        &self,
        params: OrderListCancelParams,
    ) -> anyhow::Result<WebsocketApiResponse<Box<models::OrderListCancelResponseResult>>> {
        self.trade_api_client.order_list_cancel(params).await
    }

    /// WebSocket Place new OCO - Deprecated
    ///
    /// Send in a new one-cancels-the-other (OCO) pair:
    /// `LIMIT_MAKER` + `STOP_LOSS`/`STOP_LOSS_LIMIT` orders (called *legs*),
    /// where activation of one order immediately cancels the other.
    ///
    /// This adds 1 order to `EXCHANGE_MAX_ORDERS` filter and the `MAX_NUM_ORDERS` filter
    /// Weight: 1
    ///
    /// Unfilled Order Count: 1
    ///
    /// # Arguments
    ///
    /// - `params`: [`OrderListPlaceParams`]
    ///   The parameters for this operation.
    ///
    /// # Returns
    ///
    /// [`WebsocketApiResponse<Box<models::OrderListPlaceResponseResult>>`] on success.
    ///
    /// # Errors
    ///
    /// Returns an [`anyhow::Error`] if the WebSocket request fails, if parameters are invalid, or if parsing the response fails.
    ///
    ///
    /// For full API details, see the [Binance API Documentation](https://developers.binance.com/docs/binance-spot-api-docs/websocket-api/trading-requests#place-new-oco---deprecated-trade).
    ///
    pub async fn order_list_place(
        &self,
        params: OrderListPlaceParams,
    ) -> anyhow::Result<WebsocketApiResponse<Box<models::OrderListPlaceResponseResult>>> {
        self.trade_api_client.order_list_place(params).await
    }

    /// WebSocket Place new Order list - OCO
    ///
    /// Send in an one-cancels-the-other (OCO) pair, where activation of one order immediately cancels the other.
    ///
    /// * An OCO has 2 orders called the **above order** and **below order**.
    /// * One of the orders must be a `LIMIT_MAKER/TAKE_PROFIT/TAKE_PROFIT_LIMIT` order and the other must be `STOP_LOSS` or `STOP_LOSS_LIMIT` order.
    /// * Price restrictions:
    /// * If the OCO is on the `SELL` side:
    /// * `LIMIT_MAKER/TAKE_PROFIT_LIMIT` `price` > Last Traded Price > `STOP_LOSS/STOP_LOSS_LIMIT` `stopPrice`
    /// * `TAKE_PROFIT stopPrice` > Last Traded Price > `STOP_LOSS/STOP_LOSS_LIMIT stopPrice`
    /// * If the OCO is on the `BUY` side:
    /// * `LIMIT_MAKER` `price` < Last Traded Price < `STOP_LOSS/STOP_LOSS_LIMIT` `stopPrice`
    /// * `TAKE_PROFIT stopPrice` > Last Traded Price > `STOP_LOSS/STOP_LOSS_LIMIT stopPrice`
    /// * OCOs add **2 orders** to the `EXCHANGE_MAX_ORDERS` filter and `MAX_NUM_ORDERS` filter.
    /// Weight: 1
    ///
    /// Unfilled Order Count: 2
    ///
    /// # Arguments
    ///
    /// - `params`: [`OrderListPlaceOcoParams`]
    ///   The parameters for this operation.
    ///
    /// # Returns
    ///
    /// [`WebsocketApiResponse<Box<models::OrderListPlaceOcoResponseResult>>`] on success.
    ///
    /// # Errors
    ///
    /// Returns an [`anyhow::Error`] if the WebSocket request fails, if parameters are invalid, or if parsing the response fails.
    ///
    ///
    /// For full API details, see the [Binance API Documentation](https://developers.binance.com/docs/binance-spot-api-docs/websocket-api/trading-requests#place-new-order-list---oco-trade).
    ///
    pub async fn order_list_place_oco(
        &self,
        params: OrderListPlaceOcoParams,
    ) -> anyhow::Result<WebsocketApiResponse<Box<models::OrderListPlaceOcoResponseResult>>> {
        self.trade_api_client.order_list_place_oco(params).await
    }

    /// WebSocket Place new Order list - OTO
    ///
    /// Places an OTO.
    ///
    /// * An OTO (One-Triggers-the-Other) is an order list comprised of 2 orders.
    /// * The first order is called the **working order** and must be `LIMIT` or `LIMIT_MAKER`. Initially, only the working order goes on the order book.
    /// * The second order is called the **pending order**. It can be any order type except for `MARKET` orders using parameter `quoteOrderQty`. The pending order is only placed on the order book when the working order gets **fully filled**.
    /// * If either the working order or the pending order is cancelled individually, the other order in the order list will also be canceled or expired.
    /// * When the order list is placed, if the working order gets **immediately fully filled**, the placement response will show the working order as `FILLED` but the pending order will still appear as `PENDING_NEW`. You need to query the status of the pending order again to see its updated status.
    /// * OTOs add **2 orders** to the `EXCHANGE_MAX_NUM_ORDERS` filter and `MAX_NUM_ORDERS` filter.
    /// Weight: 1
    ///
    /// Unfilled Order Count: 2
    ///
    /// # Arguments
    ///
    /// - `params`: [`OrderListPlaceOtoParams`]
    ///   The parameters for this operation.
    ///
    /// # Returns
    ///
    /// [`WebsocketApiResponse<Box<models::OrderListPlaceOtoResponseResult>>`] on success.
    ///
    /// # Errors
    ///
    /// Returns an [`anyhow::Error`] if the WebSocket request fails, if parameters are invalid, or if parsing the response fails.
    ///
    ///
    /// For full API details, see the [Binance API Documentation](https://developers.binance.com/docs/binance-spot-api-docs/websocket-api/trading-requests#place-new-order-list---oto-trade).
    ///
    pub async fn order_list_place_oto(
        &self,
        params: OrderListPlaceOtoParams,
    ) -> anyhow::Result<WebsocketApiResponse<Box<models::OrderListPlaceOtoResponseResult>>> {
        self.trade_api_client.order_list_place_oto(params).await
    }

    /// WebSocket Place new Order list - OTOCO
    ///
    /// Place an OTOCO.
    ///
    /// * An OTOCO (One-Triggers-One-Cancels-the-Other) is an order list comprised of 3 orders.
    /// * The first order is called the **working order** and must be `LIMIT` or `LIMIT_MAKER`. Initially, only the working order goes on the order book.
    /// * The behavior of the working order is the same as the [OTO](#place-new-order-list---oto-trade).
    /// * OTOCO has 2 pending orders (pending above and pending below), forming an OCO pair. The pending orders are only placed on the order book when the working order gets **fully filled**.
    /// * The rules of the pending above and pending below follow the same rules as the [Order list OCO](#new-order-list---oco-trade).
    /// * OTOCOs add **3 orders** to the `EXCHANGE_MAX_NUM_ORDERS` filter and `MAX_NUM_ORDERS` filter.
    /// Weight: 1
    ///
    /// Unfilled Order Count: 3
    ///
    /// # Arguments
    ///
    /// - `params`: [`OrderListPlaceOtocoParams`]
    ///   The parameters for this operation.
    ///
    /// # Returns
    ///
    /// [`WebsocketApiResponse<Box<models::OrderListPlaceOtocoResponseResult>>`] on success.
    ///
    /// # Errors
    ///
    /// Returns an [`anyhow::Error`] if the WebSocket request fails, if parameters are invalid, or if parsing the response fails.
    ///
    ///
    /// For full API details, see the [Binance API Documentation](https://developers.binance.com/docs/binance-spot-api-docs/websocket-api/trading-requests#place-new-order-list---otoco-trade).
    ///
    pub async fn order_list_place_otoco(
        &self,
        params: OrderListPlaceOtocoParams,
    ) -> anyhow::Result<WebsocketApiResponse<Box<models::OrderListPlaceOtocoResponseResult>>> {
        self.trade_api_client.order_list_place_otoco(params).await
    }

    /// WebSocket Place new order
    ///
    /// Send in a new order.
    ///
    /// This adds 1 order to the `EXCHANGE_MAX_ORDERS` filter and the `MAX_NUM_ORDERS` filter.
    /// Weight: 1
    ///
    /// # Arguments
    ///
    /// - `params`: [`OrderPlaceParams`]
    ///   The parameters for this operation.
    ///
    /// # Returns
    ///
    /// [`WebsocketApiResponse<Box<models::OrderPlaceResponseResult>>`] on success.
    ///
    /// # Errors
    ///
    /// Returns an [`anyhow::Error`] if the WebSocket request fails, if parameters are invalid, or if parsing the response fails.
    ///
    ///
    /// For full API details, see the [Binance API Documentation](https://developers.binance.com/docs/binance-spot-api-docs/websocket-api/trading-requests#place-new-order-trade).
    ///
    pub async fn order_place(
        &self,
        params: OrderPlaceParams,
    ) -> anyhow::Result<WebsocketApiResponse<Box<models::OrderPlaceResponseResult>>> {
        self.trade_api_client.order_place(params).await
    }

    /// WebSocket Test new order
    ///
    /// Test order placement.
    ///
    /// Validates new order parameters and verifies your signature
    /// but does not send the order into the matching engine.
    /// Weight: |Condition| Request Weight|
    /// |------------           | ------------ |
    /// |Without `computeCommissionRates`| 1|
    /// |With `computeCommissionRates`|20|
    ///
    /// # Arguments
    ///
    /// - `params`: [`OrderTestParams`]
    ///   The parameters for this operation.
    ///
    /// # Returns
    ///
    /// [`WebsocketApiResponse<Box<models::OrderTestResponseResult>>`] on success.
    ///
    /// # Errors
    ///
    /// Returns an [`anyhow::Error`] if the WebSocket request fails, if parameters are invalid, or if parsing the response fails.
    ///
    ///
    /// For full API details, see the [Binance API Documentation](https://developers.binance.com/docs/binance-spot-api-docs/websocket-api/trading-requests#test-new-order-trade).
    ///
    pub async fn order_test(
        &self,
        params: OrderTestParams,
    ) -> anyhow::Result<WebsocketApiResponse<Box<models::OrderTestResponseResult>>> {
        self.trade_api_client.order_test(params).await
    }

    /// WebSocket Place new order using SOR
    ///
    /// Places an order using smart order routing (SOR).
    ///
    /// This adds 1 order to the `EXCHANGE_MAX_ORDERS` filter and the `MAX_NUM_ORDERS` filter.
    ///
    /// Read [SOR FAQ](../faqs/sor_faq.md) to learn more.
    /// Weight: 1
    ///
    /// Unfilled Order Count: 1
    ///
    /// # Arguments
    ///
    /// - `params`: [`SorOrderPlaceParams`]
    ///   The parameters for this operation.
    ///
    /// # Returns
    ///
    /// [`WebsocketApiResponse<Vec<models::SorOrderPlaceResponseResultInner>>`] on success.
    ///
    /// # Errors
    ///
    /// Returns an [`anyhow::Error`] if the WebSocket request fails, if parameters are invalid, or if parsing the response fails.
    ///
    ///
    /// For full API details, see the [Binance API Documentation](https://developers.binance.com/docs/binance-spot-api-docs/websocket-api/trading-requests#place-new-order-using-sor-trade).
    ///
    pub async fn sor_order_place(
        &self,
        params: SorOrderPlaceParams,
    ) -> anyhow::Result<WebsocketApiResponse<Vec<models::SorOrderPlaceResponseResultInner>>> {
        self.trade_api_client.sor_order_place(params).await
    }

    /// WebSocket Test new order using SOR
    ///
    /// Test new order creation and signature/recvWindow using smart order routing (SOR).
    /// Creates and validates a new order but does not send it into the matching engine.
    /// Weight: |Condition                       | Request Weight|
    /// |------------                    | ------------ |
    /// |Without `computeCommissionRates`| 1            |
    /// |With `computeCommissionRates`   |20            |
    ///
    /// # Arguments
    ///
    /// - `params`: [`SorOrderTestParams`]
    ///   The parameters for this operation.
    ///
    /// # Returns
    ///
    /// [`WebsocketApiResponse<Box<models::SorOrderTestResponseResult>>`] on success.
    ///
    /// # Errors
    ///
    /// Returns an [`anyhow::Error`] if the WebSocket request fails, if parameters are invalid, or if parsing the response fails.
    ///
    ///
    /// For full API details, see the [Binance API Documentation](https://developers.binance.com/docs/binance-spot-api-docs/websocket-api/trading-requests#test-new-order-using-sor-trade).
    ///
    pub async fn sor_order_test(
        &self,
        params: SorOrderTestParams,
    ) -> anyhow::Result<WebsocketApiResponse<Box<models::SorOrderTestResponseResult>>> {
        self.trade_api_client.sor_order_test(params).await
    }

    /// WebSocket Listing all subscriptions
    ///
    ///
    /// Weight: 2
    ///
    /// **Data Source**:
    /// Memory
    ///
    /// # Arguments
    ///
    /// - `params`: [`SessionSubscriptionsParams`]
    ///   The parameters for this operation.
    ///
    /// # Returns
    ///
    /// [`WebsocketApiResponse<Vec<models::SessionSubscriptionsResponseResultInner>>`] on success.
    ///
    /// # Errors
    ///
    /// Returns an [`anyhow::Error`] if the WebSocket request fails, if parameters are invalid, or if parsing the response fails.
    ///
    ///
    /// For full API details, see the [Binance API Documentation](https://developers.binance.com/docs/binance-spot-api-docs/websocket-api/user-Data-Stream-requests#listing-all-subscriptions).
    ///
    pub async fn session_subscriptions(
        &self,
        params: SessionSubscriptionsParams,
    ) -> anyhow::Result<WebsocketApiResponse<Vec<models::SessionSubscriptionsResponseResultInner>>>
    {
        self.user_data_stream_api_client
            .session_subscriptions(params)
            .await
    }

    /// WebSocket Ping user data stream
    ///
    /// Ping a user data stream to keep it alive.
    ///
    /// User data streams close automatically after 60 minutes,
    /// even if you're listening to them on WebSocket Streams.
    /// In order to keep the stream open, you have to regularly send pings using the `userDataStream.ping` request.
    ///
    /// It is recommended to send a ping once every 30 minutes.
    /// Weight: 2
    ///
    /// # Arguments
    ///
    /// - `params`: [`UserDataStreamPingParams`]
    ///   The parameters for this operation.
    ///
    /// # Returns
    ///
    /// [`WebsocketApiResponse<serde_json::Value>`] on success.
    ///
    /// # Errors
    ///
    /// Returns an [`anyhow::Error`] if the WebSocket request fails, if parameters are invalid, or if parsing the response fails.
    ///
    ///
    /// For full API details, see the [Binance API Documentation](https://developers.binance.com/docs/binance-spot-api-docs/websocket-api/user-Data-Stream-requests#ping-user-data-stream-user_stream).
    ///
    pub async fn user_data_stream_ping(
        &self,
        params: UserDataStreamPingParams,
    ) -> anyhow::Result<WebsocketApiResponse<serde_json::Value>> {
        self.user_data_stream_api_client
            .user_data_stream_ping(params)
            .await
    }

    /// WebSocket Start user data stream
    ///
    /// Start a new user data stream.
    /// Weight: 2
    ///
    /// # Arguments
    ///
    /// - `params`: [`UserDataStreamStartParams`]
    ///   The parameters for this operation.
    ///
    /// # Returns
    ///
    /// [`WebsocketApiResponse<Box<models::UserDataStreamStartResponseResult>>`] on success.
    ///
    /// # Errors
    ///
    /// Returns an [`anyhow::Error`] if the WebSocket request fails, if parameters are invalid, or if parsing the response fails.
    ///
    ///
    /// For full API details, see the [Binance API Documentation](https://developers.binance.com/docs/binance-spot-api-docs/websocket-api/user-Data-Stream-requests#start-user-data-stream-user_stream).
    ///
    pub async fn user_data_stream_start(
        &self,
        params: UserDataStreamStartParams,
    ) -> anyhow::Result<WebsocketApiResponse<Box<models::UserDataStreamStartResponseResult>>> {
        self.user_data_stream_api_client
            .user_data_stream_start(params)
            .await
    }

    /// WebSocket Stop user data stream
    ///
    /// Explicitly stop and close the user data stream.
    /// Weight: 2
    ///
    /// # Arguments
    ///
    /// - `params`: [`UserDataStreamStopParams`]
    ///   The parameters for this operation.
    ///
    /// # Returns
    ///
    /// [`WebsocketApiResponse<serde_json::Value>`] on success.
    ///
    /// # Errors
    ///
    /// Returns an [`anyhow::Error`] if the WebSocket request fails, if parameters are invalid, or if parsing the response fails.
    ///
    ///
    /// For full API details, see the [Binance API Documentation](https://developers.binance.com/docs/binance-spot-api-docs/websocket-api/user-Data-Stream-requests#stop-user-data-stream-user_stream).
    ///
    pub async fn user_data_stream_stop(
        &self,
        params: UserDataStreamStopParams,
    ) -> anyhow::Result<WebsocketApiResponse<serde_json::Value>> {
        self.user_data_stream_api_client
            .user_data_stream_stop(params)
            .await
    }

    /// WebSocket Subscribe to User Data Stream
    ///
    /// Subscribe to the User Data Stream in the current WebSocket connection.
    /// Weight: 2
    ///
    /// # Arguments
    ///
    /// - `params`: [`UserDataStreamSubscribeParams`]
    ///   The parameters for this operation.
    ///
    /// # Returns
    ///
    /// [`WebsocketApiResponse<Box<models::UserDataStreamSubscribeResponseResult>>`] on success.
    ///
    /// # Errors
    ///
    /// Returns an [`anyhow::Error`] if the WebSocket request fails, if parameters are invalid, or if parsing the response fails.
    ///
    ///
    /// For full API details, see the [Binance API Documentation](https://developers.binance.com/docs/binance-spot-api-docs/websocket-api/user-Data-Stream-requests#subscribe-to-user-data-stream-user_stream).
    ///
    pub async fn user_data_stream_subscribe(
        &self,
        params: UserDataStreamSubscribeParams,
    ) -> anyhow::Result<(
        WebsocketApiResponse<Box<models::UserDataStreamSubscribeResponseResult>>,
        Arc<WebsocketStream<UserDataStreamEventsResponse>>,
    )> {
        let response = self
            .user_data_stream_api_client
            .user_data_stream_subscribe(params)
            .await?;
        let stream = create_stream_handler::<UserDataStreamEventsResponse>(
            WebsocketBase::WebsocketApi(self.websocket_api_base.clone()),
            random_string(),
            None,
        )
        .await;

        Ok((response, stream))
    }

    /// WebSocket Subscribe to User Data Stream through signature subscription
    ///
    ///
    /// Weight: 2
    ///
    /// # Arguments
    ///
    /// - `params`: [`UserDataStreamSubscribeSignatureParams`]
    ///   The parameters for this operation.
    ///
    /// # Returns
    ///
    /// [`WebsocketApiResponse<Box<models::UserDataStreamSubscribeResponseResult>>`] on success.
    ///
    /// # Errors
    ///
    /// Returns an [`anyhow::Error`] if the WebSocket request fails, if parameters are invalid, or if parsing the response fails.
    ///
    ///
    /// For full API details, see the [Binance API Documentation](https://developers.binance.com/docs/binance-spot-api-docs/websocket-api/user-Data-Stream-requests#subscribe-to-user-data-stream-through-signature-subscription-user_data).
    ///
    pub async fn user_data_stream_subscribe_signature(
        &self,
        params: UserDataStreamSubscribeSignatureParams,
    ) -> anyhow::Result<(
        WebsocketApiResponse<Box<models::UserDataStreamSubscribeResponseResult>>,
        Arc<WebsocketStream<UserDataStreamEventsResponse>>,
    )> {
        let response = self
            .user_data_stream_api_client
            .user_data_stream_subscribe_signature(params)
            .await?;
        let stream = create_stream_handler::<UserDataStreamEventsResponse>(
            WebsocketBase::WebsocketApi(self.websocket_api_base.clone()),
            random_string(),
            None,
        )
        .await;

        Ok((response, stream))
    }

    /// WebSocket Unsubscribe from User Data Stream
    ///
    /// Stop listening to the User Data Stream in the current WebSocket connection.
    ///
    /// Note that `session.logout` will only close the subscription created with `userdataStream.subscribe` but not subscriptions opened with `userDataStream.subscribe.signature`.
    /// Weight: 2
    ///
    /// # Arguments
    ///
    /// - `params`: [`UserDataStreamUnsubscribeParams`]
    ///   The parameters for this operation.
    ///
    /// # Returns
    ///
    /// [`WebsocketApiResponse<serde_json::Value>`] on success.
    ///
    /// # Errors
    ///
    /// Returns an [`anyhow::Error`] if the WebSocket request fails, if parameters are invalid, or if parsing the response fails.
    ///
    ///
    /// For full API details, see the [Binance API Documentation](https://developers.binance.com/docs/binance-spot-api-docs/websocket-api/user-Data-Stream-requests#unsubscribe-from-user-data-stream).
    ///
    pub async fn user_data_stream_unsubscribe(
        &self,
        params: UserDataStreamUnsubscribeParams,
    ) -> anyhow::Result<WebsocketApiResponse<serde_json::Value>> {
        self.user_data_stream_api_client
            .user_data_stream_unsubscribe(params)
            .await
    }
}
